//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.quickserver.util.io;

import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.quickserver.net.server.ClientHandler;
import org.quickserver.util.Assertion;

public class ByteBufferInputStream extends InputStream {
    private static final Logger logger = Logger.getLogger(ByteBufferInputStream.class.getName());
    private final ArrayList bufferList;
    private ClientHandler handler;
    private CharsetDecoder decoder;
    private CharsetEncoder encoder;
    private StringBuilder strings;
    private int pos = 0;
    private int index = -1;
    private int start = 0;
    private boolean lookingForLineFeed = false;

    static {
        logger.setLevel(Level.INFO);
    }

    public static void setDebug(boolean flag) {
        if (flag) {
            logger.setLevel(Level.FINEST);
        } else {
            logger.setLevel(Level.INFO);
        }

    }

    public static boolean isLoggable(Level level) {
        return logger.isLoggable(level);
    }

    public ByteBufferInputStream(ArrayList bufferList, ClientHandler handler, String charset) {
        if (bufferList != null && handler != null) {
            this.bufferList = bufferList;
            this.handler = handler;
            Charset _charset = Charset.forName(charset);
            this.decoder = _charset.newDecoder();
            this.encoder = _charset.newEncoder();
            this.strings = new StringBuilder();
        } else {
            throw new IllegalArgumentException("ArrayList or ClientHandler was null.");
        }
    }

    public synchronized int availableOnlyInByteBuffer() {
        int count = 0;
        ByteBuffer byteBuffer = null;
        int size = this.bufferList.size();

        for(int c = 0; c < size; ++c) {
            byteBuffer = (ByteBuffer)this.bufferList.get(c);
            count += byteBuffer.remaining();
        }

        logger.finest("count: " + count);
        return count;
    }

    public synchronized int available() {
        int count = 0;
        ByteBuffer byteBuffer = null;
        int p;
        if (this.lookingForLineFeed) {
        	 char c = Character.MIN_VALUE;
            if (this.strings.length() != 0) {
                c = this.strings.charAt(0);
                if (c == '\n') {
                    this.strings.deleteCharAt(0);
                    this.lookingForLineFeed = false;
                }
            } else {
                while(!this.bufferList.isEmpty()) {
                    byteBuffer = (ByteBuffer)this.bufferList.get(0);
                    if (byteBuffer.remaining() != 0) {
                        p = byteBuffer.position();
                        c = (char)byteBuffer.get(p);
                        if (c == '\n') {
                            byteBuffer.get();
                            this.lookingForLineFeed = false;
                        }
                        break;
                    }

                    this.returnBufferBack();
                }
            }
        }

         count = count + this.strings.length();
        int size = this.bufferList.size();

        for(p = 0; p < size; ++p) {
            byteBuffer = (ByteBuffer)this.bufferList.get(p);
            count += byteBuffer.remaining();
        }

        return count;
    }

    public synchronized void close() throws IOException {
        if (this.handler.getSocketChannel() != null) {
            this.handler.getSocketChannel().close();
        }

    }

    public boolean markSupported() {
        return false;
    }

    public synchronized int read() throws IOException {
        this.handler.isConnected();
        if (this.strings.length() != 0) {
            this.addStringsBackAsBuffer();
        }

        if (this.bufferList.isEmpty()) {
            try {
                this.wait();
            } catch (InterruptedException var3) {
                logger.warning("InterruptedException: " + var3);
                return -1;
            }

            if (this.bufferList.isEmpty()) {
                return -1;
            }
        }

        ByteBuffer byteBuffer = null;

        while(!this.bufferList.isEmpty()) {
            byteBuffer = (ByteBuffer)this.bufferList.get(0);
            if (byteBuffer.remaining() == 0) {
                this.returnBufferBack();
            } else {
                if (!this.lookingForLineFeed) {
                    return byteBuffer.get();
                }

                int lflfChar = byteBuffer.get();
                this.lookingForLineFeed = false;
                if (lflfChar != 10) {
                    return lflfChar;
                }
            }
        }

        return this.read();
    }

    public int read(byte[] b) throws IOException {
        return this.read(b, 0, b.length);
    }

    public synchronized int read(byte[] b, int off, int len) throws IOException {
        this.handler.isConnected();
        if (this.strings.length() != 0) {
            this.addStringsBackAsBuffer();
        }

        if (this.bufferList.isEmpty()) {
            try {
                this.wait();
            } catch (InterruptedException var10) {
                logger.warning("InterruptedException: " + var10);
                return -1;
            }

            if (this.bufferList.isEmpty()) {
                return -1;
            }
        }

        ByteBuffer byteBuffer = null;
        int read = 0;
        int remaining = 0;
        int toRead = len;

        do {
            byteBuffer = (ByteBuffer)this.bufferList.get(0);
            remaining = byteBuffer.remaining();
            if (remaining == 0) {
                this.returnBufferBack();
            } else {
                if (this.lookingForLineFeed) {
                    int p = byteBuffer.position();
                    byte lflfChar = byteBuffer.get(p);
                    this.lookingForLineFeed = false;
                    if (lflfChar == 10) {
                        byteBuffer.get();
                        continue;
                    }
                }

                if (remaining >= toRead) {
                    byteBuffer.get(b, off, toRead);
                    read += toRead;
                    return read;
                }

                byteBuffer.get(b, off, remaining);
                off += remaining;
                read += remaining;
                toRead -= remaining;
            }
        } while(!this.bufferList.isEmpty());

        return read;
    }

    public long skip(long n) throws IOException {
        if (n < 0L) {
            return 0L;
        } else {
            int s;
            for(s = 0; (long)s < n && this.read() != -1; ++s) {
                ;
            }

            return (long)s;
        }
    }

    private void addStringsBackAsBuffer() {
        try {
            ByteBuffer borrowBuffer = null;
            ByteBuffer bb = this.encoder.encode(CharBuffer.wrap(this.strings));
            this.strings.setLength(0);

            do {
                if (borrowBuffer == null) {
                    borrowBuffer = (ByteBuffer)this.handler.getServer().getByteBufferPool().borrowObject();
                }

                borrowBuffer.put(bb.get());
                if (!borrowBuffer.hasRemaining()) {
                    borrowBuffer.flip();
                    this.bufferList.add(0, borrowBuffer);
                    borrowBuffer = null;
                }
            } while(bb.hasRemaining());

            if (borrowBuffer != null) {
                borrowBuffer.flip();
                this.bufferList.add(0, borrowBuffer);
            }
        } catch (Exception var3) {
            logger.warning("Error : " + var3);
        }

        this.start = 0;
        this.index = -1;
        this.pos = 0;
    }

    private void returnBufferBack() {
        this.returnBufferBack((ByteBuffer)this.bufferList.remove(0));
    }

    private void returnBufferBack(ByteBuffer byteBuffer) {
        try {
            this.handler.getServer().getByteBufferPool().returnObject(byteBuffer);
        } catch (Exception var3) {
            logger.warning("Error while returning ByteBuffer to pool: " + var3);
        }

    }

    public synchronized boolean isLineReady() throws IOException {
        this.handler.isConnected();
        boolean result = false;
        result = this.isLineReadyForStringBuilder();
        if (!result && !this.bufferList.isEmpty()) {
            ByteBuffer byteBuffer = null;
            CharBuffer charBuffer = null;

            while(!result && !this.bufferList.isEmpty()) {
                byteBuffer = (ByteBuffer)this.bufferList.get(0);
                if (byteBuffer.remaining() == 0) {
                    this.returnBufferBack();
                } else {
                    charBuffer = this.decoder.decode(byteBuffer);
                    if (charBuffer == null) {
                        this.returnBufferBack();
                    } else {
                        this.strings.append(charBuffer);
                        this.returnBufferBack();
                        result = this.isLineReadyForStringBuilder();
                    }
                }
            }

            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("result: " + result);
            }

            return result;
        } else {
            if (logger.isLoggable(Level.FINEST)) {
                logger.finest("result: " + result);
            }

            return result;
        }
    }

    private boolean isLineReadyForStringBuilder() {
        if (this.index != -1) {
            return true;
        } else {
            int stringsLength = this.strings.length();

            while(this.pos < stringsLength) {
                char c = this.strings.charAt(this.pos);
                if (c == '\n') {
                    if (!this.lookingForLineFeed) {
                        this.index = this.pos++;
                        return true;
                    }

                    this.strings.deleteCharAt(0);
                    --stringsLength;
                    this.lookingForLineFeed = false;
                } else {
                    if (c == '\r') {
                        this.index = this.pos;
                        this.lookingForLineFeed = true;
                        ++this.pos;
                        return true;
                    }

                    ++this.pos;
                    this.lookingForLineFeed = false;
                }
            }

            return false;
        }
    }

    public synchronized String readLine() throws IOException {
        if (this.index == -1) {
            while(!this.isLineReady()) {
                try {
                    this.wait();
                } catch (InterruptedException var3) {
                    logger.warning("InterruptedException: " + var3);
                    return null;
                }
            }
        }

        int stringsLength = this.strings.length();
        Assertion.affirm(this.index <= stringsLength);
        String data = this.strings.substring(this.start, this.index);
        if (this.pos < stringsLength) {
            this.strings.delete(0, this.pos);
        } else {
            this.strings.setLength(0);
        }

        this.start = 0;
        this.pos = this.start;
        this.index = -1;
        return data;
    }

    public void dumpContent() {
        if (logger.isLoggable(Level.FINE)) {
            logger.fine("Start of dump..");
            ArrayList var1 = this.bufferList;
            synchronized(this.bufferList) {
                int size = this.bufferList.size();
                ByteBuffer byteBuffer = null;
                if (this.strings.length() != 0) {
                    logger.fine("[decoded] " + this.strings);
                }

                int c = 0;

                while(true) {
                    if (c >= size) {
                        break;
                    }

                    byteBuffer = (ByteBuffer)this.bufferList.get(c);

                    try {
                        logger.fine("[" + c + "] " + this.decoder.decode(byteBuffer.duplicate()));
                    } catch (Exception var6) {
                        logger.fine("[" + c + "] Error : " + var6);
                    }

                    ++c;
                }
            }

            logger.fine("End of dump..");
        }
    }
}
